`timescale 1ps/1ps
module RAM40_4K (RDATA, RCLK, RCLKE, RE, RADDR, WCLK, WCLKE, WE, WADDR, MASK, WDATA);
output [15:0] RDATA;
input RCLK;
input RCLKE;
input RE;
input [10:0] RADDR;
input WCLK;
input WCLKE;
input WE;
input [10:0] WADDR;
input [15:0] MASK;
input [15:0] WDATA;

assign (weak0, weak1) MASK = 16'b0;

parameter DATA_WIDTH_W = 16;
parameter DATA_WIDTH_R = 16;

localparam WRITE_MODE = (DATA_WIDTH_W == 2)? 3 : (DATA_WIDTH_W == 4)? 2 : (DATA_WIDTH_W == 8)? 1 : 0; /// can be integer 0(256X16 mode) or 1(512X8 mode) or 2(1024X4 mode) or 3(2048X2 mode)
localparam READ_MODE = (DATA_WIDTH_R == 2)? 3 : (DATA_WIDTH_R == 4)? 2 : (DATA_WIDTH_R == 8)? 1 : 0;  /// can be integer 0(256X16 mode) or 1(512X8 mode) or 2(1024X4 mode) or 3(2048X2 mode)


parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;

//For Debugging Purposes

wire [15:0] RD;
wire [15:0] WD;
wire [15:0] MASK_RAM;

reg [10:8] RADDR_reg;
always @(posedge RCLK) begin
    RADDR_reg[10:8] <= RADDR[10:8];
end

read_data_decoder read_decoder_inst (
    .di(RD),
    .ai(RADDR_reg[10:8]),
    .do(RDATA)
);
defparam read_decoder_inst.READ_MODE = READ_MODE;

write_data_decoder write_decoder_inst (
    .di(WDATA),
    .do(WD)
);
defparam write_decoder_inst.WRITE_MODE = WRITE_MODE;

mask_decoder mask_decoder_inst(
    .mi(MASK),
    .ai(WADDR[10:8]),
    .mo(MASK_RAM)
);
defparam mask_decoder_inst.WRITE_MODE = WRITE_MODE;

RAM4K ram_inst (
    .RDATA(RD),
    .RCLK(RCLK),
    .RCLKE(RCLKE),
    .RE(RE),
    .RADDR(RADDR[7:0]),
    .WCLK(WCLK),
    .WCLKE(WCLKE),
    .WE(WE),
    .WADDR(WADDR[7:0]),
    .MASK(MASK_RAM),
    .WDATA(WD));

defparam ram_inst.INIT_0 = INIT_0;
defparam ram_inst.INIT_1 = INIT_1;
defparam ram_inst.INIT_2 = INIT_2;
defparam ram_inst.INIT_3 = INIT_3;
defparam ram_inst.INIT_4 = INIT_4;
defparam ram_inst.INIT_5 = INIT_5;
defparam ram_inst.INIT_6 = INIT_6;
defparam ram_inst.INIT_7 = INIT_7;
defparam ram_inst.INIT_8 = INIT_8;
defparam ram_inst.INIT_9 = INIT_9;
defparam ram_inst.INIT_A = INIT_A;
defparam ram_inst.INIT_B = INIT_B;
defparam ram_inst.INIT_C = INIT_C;
defparam ram_inst.INIT_D = INIT_D;
defparam ram_inst.INIT_E = INIT_E;
defparam ram_inst.INIT_F = INIT_F;

endmodule
